
// is 16-bit code
__asm__(".code16gcc");

// include head file
#include "loader.h"

// define global static var
// define memory struct
boot_info_t boot_info;
// define gdt_table struct
uint16_t gdt_table[][4] = {
    {0, 0, 0, 0},
    // 0xffff:segment limit
    // 0x0000:base address
    // 0x9a00: code segment,read/exec
    // 0x00fc: granularity（颗粒度）
    // 0x9200: data segment,read/write
    {0xffff, 0x0000, 0x9a00, 0x00fc},
    {0xffff, 0x0000, 0x9200, 0x00fc},
};

/**
 * @brief print the msg(String) in terminal
 *
 * @param msg string to print
 */
static void show_msg(char *msg)
{
    char c;
    while ((c = *msg++) != '\0')
    {
        __asm__ __volatile__(
            "mov $0xe, %%ah\n\t"
            "mov %[ch],%%al\n\t"
            "int $0x10" ::[ch] "r"(c));
    }
}

/**
 * @brief detect message, how manay size can use by OS
 *
 */
void detect_memory(void)
{
    SMAP_entry_t smap_entry;
    uint32_t contID = 0;
    uint32_t signature, bytes;
    boot_info.ram_region_count = 0;
    for (int i = 0; i < BOOT_RAM_REGION_MAX; i++)
    {
        SMAP_entry_t *entry = &smap_entry;
        __asm__ __volatile__("int  $0x15"
                             : "=a"(signature), "=c"(bytes), "=b"(contID)
                             : "a"(0xE820), "b"(contID), "c"(24), "d"(0x534D4150), "D"(entry));

        // detect_memory is failed
        if (signature != 0x534D4150)
        {
            show_msg("failed detect memory!!!\r");
            return; // error
        }
        // memeory can't use
        if (bytes > 20 && (entry->ACPI & 0x0001) == 0)
        {
            continue;
        }
        // add entry into boot_info_t array
        if (entry->Type == 1)
        {
            boot_info.ram_region_cfg[boot_info.ram_region_count].start = entry->BaseL;
            boot_info.ram_region_cfg[boot_info.ram_region_count].size = entry->LengthL;
            boot_info.ram_region_count++;
        }
        // contID is zero, end while loop
        if (contID == 0)
        {
            break;
        }
    }
    // print message, function execute ok!!
    show_msg("detect_memory is finnsh\r\n");

    //  show_msg only can print string, it is not print function, can't print %d, can't  transformation number to string
    // uint32_t count=0;
    // for (int i = 0; i < boot_info.ram_region_count; i++)
    // {
    //     count += boot_info.ram_region_cfg[i].size;
    // }
    // all_size_K = count>>4;
    // show_msg("all free memory size is");
}



void switch_protect_mode()
{
    cli();

    // open A20 address line
    uint8_t port_value = inb(0x92);
    outb(0x92, port_value | 2);

    // load global gdt,use instruction lgdt
    lgdt((uint32_t)gdt_table, sizeof(gdt_table));

    // modify CR0 register PE bit to number 1
    uint16_t cr0 = read_cr0();
    write_cr0(cr0 | 1 << 0);

    // move to 32 bit
    far_jump(8, (uint32_t)protect_mode_entry);

    // sti();
}

void loader_entry()
{

    show_msg("\r\n....loading....\r\n");
    detect_memory();
    switch_protect_mode();
}
